import os
import time
import cv2
from Module.xRayDetection.ftp_tree import *
from mylibs.lib import *
__appname__ = '章鱼博士'

from universal.root_path import init_log,cvimg_to_qtimg
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QPixmap

from PyQt5.QtCore import QTimer,QProcess,QThread,pyqtSignal,\
    QWaitCondition,QMutex,QFileInfo,QEvent
from Module.IndustryModel.CameraSDK_class import CameraSDK
from universal.root_path import drawDetectBox_NoCls,news_box2
from universal.widget_common import Table_widget,lineEdit_act_file,\
    Table_widget_setItem


class Worker(QThread):
    sinOut = pyqtSignal()

    def __init__(self, q_image,parent=None):
        super(Worker, self).__init__(parent)
        self.working = False
        self._isPause = False
        self.q_image = q_image
        self.cond = QWaitCondition()
        self.mutex = QMutex()
        self.lock = threading.RLock()

    def __del__(self):
        self.working = False
        self.wait()

    def pause(self):
        self._isPause = True

    def resume(self):
        self._isPause = False
        self.cond.wakeAll()

    def endThread(self):
        self.working = False

    def  startThread(self):
        self.working = True

    def run(self):
        while self.working == True:
            with self.lock:
                # if self._isPause:
                #     self.cond.wait(self.mutex)
                self.sinOut.emit()
                self.msleep(150)


class WorkerLabel(QThread):
    sinOut = pyqtSignal(object)

    def __init__(self, q_pixImage,parent=None):
        super(WorkerLabel, self).__init__(parent)
        self.working = False
        self.q_pixImage = q_pixImage
        self.mutex = QMutex()
        self.lock = threading.RLock()

    def __del__(self):
        self.working = False
        self.wait()

    def endThread(self):
        self.working = False

    def startThread(self):
        self.working = True

    def run(self):
        while self.working == True:
            with self.lock:
                img = self.q_pixImage.get()
                self.sinOut.emit(img)
                self.msleep(150)

class IndustryWidget_(QWidget):
    def __init__(self):
        super(IndustryWidget_,self).__init__()
        #self.setWindowFlags(Qt.FramelessWindowHint)  # 无边框化
        timeStart1111 = time.time()

        self.CameraSDK_ = CameraSDK()
        self.q_image = queue.Queue()
        self.q_image.maxsize = 5
        self.q_pixImage = queue.Queue()
        self.q_pixImage.maxsize = 5
        self.preWeights = ''
        self.weights = ''
        self.yoloModel = None
        self.cfg = {}
        timeStart3 = time.time()
        self.w1 = 1
        self.h1 = 1
        self.proj_path = ''
        self.buf_lock = threading.RLock()
        self.zoomWidget = ZoomWidget()
        self.init_widget()
        self.function()
        self.Button_Color()
        self.init_thread()
        timeStart4 = time.time()
        print(timeStart4-timeStart3,timeStart3-timeStart1111)

    def function(self):
        self.runbutton.clicked.connect(self.startRun)
        self.stopbutton.clicked.connect(self.stopRun)
        self.Find_button.clicked.connect(self.find_device)
        self.Open_button.clicked.connect(self.openDevice)
        self.Close_button.clicked.connect(self.closeDvice)
        self.gather_Button1.clicked.connect(self.startGrabbing)
        self.gather_Button2.clicked.connect(self.stopGrabbing)
        self.gather_radioButton1.clicked.connect(self.continueMode)
        self.gather_radioButton2.clicked.connect(self.softTriggerMode)
        self.gather_Button3.clicked.connect(self.softTrigger)
        self.parameter_button2.clicked.connect(self.setParameter)
        self.parameter_button1.clicked.connect(self.getParameter)

    def SaveImg(self):
        try:
            save_path = os.path.join(self.proj_path,'SaveImg')
            if not os.path.exists(save_path):
                os.mkdir(save_path)
            cv2.imwrite(save_path, self.cvimg)
        except Exception as e:
           print(str(e))

    def getParameter(self):
        self.CameraSDK_.Get_CamParameter()
        self.TabelParameter.setItem(0, 0, QTableWidgetItem(self.CameraSDK_.frame_rate))
        self.TabelParameter.setItem(1, 0, QTableWidgetItem(self.CameraSDK_.exposure_time))
        self.TabelParameter.setItem(2, 0, QTableWidgetItem(self.CameraSDK_.gain))

    def setParameter(self):
        frame_rate = self.TabelParameter.item(0, 1).text()
        exposure_time = self.TabelParameter.item(1, 1).text()
        gain = self.TabelParameter.item(2, 1).text()
        self.CameraSDK_.Set_CamParameter(frame_rate,exposure_time,gain)

    def softTrigger(self):
        self.CameraSDK_.Set_Trigger_once()

    def openDevice(self):
        self.CameraSDK_.open_device()
        self.LockButton()

    def closeDvice(self):
        self.CameraSDK_.close_device()
        self.LockButton()

    def stopGrabbing(self):
        self.CameraSDK_.stop_grabbing()
        self.LockButton()

    def find_device(self):
        from Module.IndustryModel.CameraSDK_class import init_CameraDll
        ret = init_CameraDll()
        if ret == False:
            news = '没有检测到相机驱动'
            customMsgBox, cancelButton = news_box2(news)
            button = customMsgBox.clickedButton()
            if button == cancelButton:
                return
        self.CameraSDK_.find_device()
        self.LockButton()

    def init_thread(self):
        self.isStartDetect = False
        self.qPixImg = None
        self.cvimg = None
        self.thread = Worker(self.q_image)
        self.thread.sinOut.connect(self.slotPic)
        self.timer = QTimer()
        self.timer.timeout.connect(self.pic2Label)

    def slotPic(self):
        try:
            img = self.getImageBuffer()
            self.cvimg = img
            self.qPixImg = None
            if self.isStartDetect == True:
                img = self.runDetect(img)
            qimg = cvimg_to_qtimg(img)
            # qPixImg = QtGui.QPixmap(qimg).scaled(self.label.width(), self.label.height()) #label
            self.qPixImg = qimg
        except Exception as e:
            print(str(e))

    def pic2Label(self):
        try:
            if self.qPixImg != None:
                self.loadImg(self.qPixImg)
            else:
                qimg = cvimg_to_qtimg(self.cvimg)
                self.loadImg(qimg)
        except Exception as e:
            print(str(e))

    def isOpenCamera(self):
        return self.CameraSDK_.isOpen

    def isGrabbingImg(self):
        return self.CameraSDK_.isGrabbing

    def isCamMode(self):
        return self.CameraSDK_.isCamMode

    def isFindCam(self):
        return self.CameraSDK_.isFindCam

    def getImageBuffer(self):
        return self.CameraSDK_.obj_cam_operation.cvImage

    def openCamera(self):
        ret = -1
        nDeviceNum = self.CameraSDK_.find_device()
        if nDeviceNum < 1:
            TextBrowserNews(self.textNews, 'Find no device')
            return ret
        ret = self.CameraSDK_.open_device()
        if 0 != ret:
            TextBrowserNews(self.textNews, 'Open device failed')
            return ret
        self.getParameter()
        return ret

    def stopCamera(self):
        self.CameraSDK_.stop_grabbing()
        self.CameraSDK_.close_device()

    def endTimerAndThread(self):
        try:
            self.timer.stop()
            self.isStartDetect = False
            # self.thread.lock.release()
            self.thread.endThread()
            self.thread.terminate()
            self.thread.wait()
        except Exception as e:
            print(str(e))

    def clearModelAndThread(self):
        if self.yoloModel != None:
            del self.yoloModel
        if self.thread != None and self.thread.isFinished():
            del self.thread
        # import gc
        # import torch
        # gc.collect()
        # torch.cuda.empty_cache()

    def startGrabbing(self):
        self.q_image.queue.clear()
        self.CameraSDK_.start_grabbing(self.q_image)
        self.timer.start(20)
        self.thread.startThread()#
        self.thread.start()
        self.LockButton()

        # self.Get_Pic = threading.Thread(target=self.getpic, args=(self.q_image,))
        # self.Get_Pic.daemon = True
        # self.Get_Pic.start()

    def getpic(self):
        while True:
            time.sleep(0.1)
            try:
                self.buf_lock.acquire()
                img = self.q_image.get()
                if img.all() == None:
                    continue
                if self.isStartDetect == True:
                    img = self.runDetect(img)
                img = cvimg_to_qtimg(img)
                # img = QtGui.QPixmap(img).scaled(self.label.width(), self.label.height())
                # img = QPixmap.fromImage(img)
                self.loadImg(img)
                # self.label.setPixmap(img)
                self.buf_lock.release()
            except Exception as e:
                self.buf_lock.release()
                print(str(e))

    def paintCanvas(self):
        self.canvas.scale = 0.01 * self.zoomWidget.value()  #
        # self.canvas.adjustSize()
        self.canvas.update()

    def scaleFitWindow(self):
        a1 = self.w1 / self.h1
        w2 = self.canvas.pixmap.width() - 0.0
        h2 = self.canvas.pixmap.height() - 0.0
        a2 = w2 / h2
        return self.w1 / w2 if a2 >= a1 else self.h1 / h2

    def adjustScale(self):
        value = self.scaleFitWindow()
        self.zoomWidget.setValue(int(100 * value))

    def loadImg(self, qImg):
        pixmap = QPixmap.fromImage(qImg)
        self.canvas.loadPixmap(pixmap)
        # self.adjustScale()
        self.paintCanvas()

    def startRun(self):
        from Module.IndustryModel.CameraSDK_class import init_CameraDll
        if init_CameraDll() is False:
            news = '没有检测到相机驱动'
            customMsgBox,cancelButton = news_box2(news)
            button = customMsgBox.clickedButton()
            if button == cancelButton:
                return False
        self.stopCamera()
        if self.openCamera() != 0:
            TextBrowserNews(self.textNews, 'Open device failed')
            return False
        self.startGrabbing()
        self.isStartDetect = True
        TextBrowserNews(self.textNews, 'startRun is Success')
        return True

    def stopRun(self):
        self.endTimerAndThread()

    def runDetect(self, img):
        try:
            time1 = time.time()
            if img.ndim == 4:
                img_result = cv2.cvtColor(img.astype(np.uint8), cv2.COLOR_RGBA2RGB)
            elif img.ndim == 3:
                img_result = img.astype(np.uint8)
            elif img.ndim == 2:
                img_result = cv2.cvtColor(img.astype(np.uint8), cv2.COLOR_GRAY2RGB)
            if self.yoloModel == None:
                return img_result
            conf = self.conf_edit.text()
            _, det = self.yoloModel.detect(img_result, float(conf), classes=[])
            drawDetectBox_NoCls(img_result,det,None)
            time2 = time.time()
            print("time:",time2 - time1)
            TextBrowserNews(self.textNews, "检测时间:{:.3f}".format(time2 - time1))
            return img_result
        except Exception as e:
            print(str(e))
            return img

    def init_widget(self):
        self.layout = QHBoxLayout(self)       #整体横向布局
        #--------------左侧界面&布局-------------
        # ---------设置模式界面---------+
        self.ModelPage()
        #---------整体布局(左右)----------
        self.canvas = Canvas(parent=self)
        self.layout.addWidget(self.canvas)

    def ModelPage(self): #模式界面选择
        self.leftwidget = QTabWidget()
        self.leftwidget.setMaximumHeight(935)
        self.leftwidget.currentChanged.connect(self.tabChanged)
        self.WidgetRunModel()
        self.WidgetDebugger()
        self.leftwidget.addTab(self.Widget_RunModel, "运行")
        self.leftwidget.addTab(self.Widget_Debugger, "调试")

    def tabChanged(self):#界面切换触发
        if self.leftwidget.currentIndex() == 0:
            self.isStartDetect = True
        if self.leftwidget.currentIndex() == 1:
            self.isStartDetect = False
            self.LockButton()

    def LockButton(self):
        self.Close_button.setEnabled(self.isFindCam() and self.isOpenCamera())
        self.Open_button.setEnabled(self.isFindCam() and (not self.isOpenCamera()))
        self.gather_Button1.setEnabled(self.isOpenCamera() and (not self.isGrabbingImg()))
        self.gather_Button2.setEnabled(self.isOpenCamera() and self.isGrabbingImg())
        self.gather_Button3.setEnabled(self.isGrabbingImg() and self.isCamMode())
        self.gather_Button4.setEnabled(self.isGrabbingImg())
        self.parameter_button1.setEnabled(self.isOpenCamera())
        self.parameter_button2.setEnabled(self.isOpenCamera())
        self.gather_radioButton1.setChecked(not self.isCamMode())
        self.gather_radioButton2.setChecked(self.isCamMode())
        self.gather_radioButton1.setEnabled(self.isOpenCamera())#
        self.gather_radioButton2.setEnabled(self.isOpenCamera())

    def WidgetRunModel(self): #运行模式界面
        self.Widget_RunModel = QWidget(self)
        Layout_RunModel = QVBoxLayout(self.Widget_RunModel)
        self.textNews = QTextBrowser()
        self.textNews.document().setMaximumBlockCount(100)
        self.DetectParameter = Table_widget(self,2, 2) #登录表格参数;2行2列

        ModelPath  = lineEdit_act_file(self,"Excel files (*.pt)")
        self.conf_edit = QLineEdit('')

        self.conf_edit.setValidator(QRegExpValidator(QRegExp("1|(0[\.][0-9]{1,2})"), self))
        self.conf_edit.setText('0.5')
        ModelPath.textChanged.connect(lambda: self.LineEvent(ModelPath))

        name_list = ["模型选择", "置信度"]
        Table_widget_setItem(self.DetectParameter, name_list)
        self.DetectParameter.setCellWidget(0, 1, ModelPath)
        self.DetectParameter.setCellWidget(1, 1, self.conf_edit)

        self.runbutton = QPushButton('运行')
        self.stopbutton = QPushButton('停止')
        Layout_RunModel.addWidget(self.textNews)
        Layout_RunModel.addWidget(self.DetectParameter)
        Layout_RunModel.addWidget(self.runbutton)
        Layout_RunModel.addWidget(self.stopbutton)
        # return Layout_RunModel

    def LineEvent(self,path):
        self.weights = path.text()
        if os.path.exists(self.weights):
            if self.weights.endswith('.pt'):
                TextBrowserNews(self.textNews, self.weights)

        else:
            news = '该路径不存在!'
            TextBrowserNews(self.textNews,news)
            return

        if self.preWeights == '' or self.weights == '' or self.preWeights != self.weights:
            self.preWeights = self.weights
            self.cfg = {'device': '0', 'logger': init_log()}
            self.loadModel = threading.Thread(target=self.loadModel_, args=(self.cfg, self.weights))
            self.loadModel.daemon = True
            self.loadModel.start()


    def loadModel_(self,cfg,model):
        TextBrowserNews(self.textNews, '加载模型中')
        from Module.xRayDetection.xray.yolov5 import YOLOV5
        self.clearModelAndThread()
        self.yoloModel = YOLOV5(weights=model, device=cfg['device'], logger=cfg['logger'], git_dir ='DeepLearning/downloads')
        TextBrowserNews(self.textNews, '加载模型成功')


    def WidgetDebugger(self): #调试模式界面
        self.Widget_Debugger = QFrame(self)
        Debugger_RunModel = QVBoxLayout(self.Widget_Debugger)
        #--------第一个Group-------
        initialize = QGroupBox('初始化')
        self.Find_button = QPushButton('查找设备')
        self.Open_button = QPushButton('打开设备')
        self.Close_button = QPushButton('关闭设备')
        Group1_layout1 = QVBoxLayout(initialize)
        Group1_layout2 = QHBoxLayout()
        Group1_layout2.addWidget(self.Open_button)
        Group1_layout2.addWidget(self.Close_button)
        Group1_layout1.addWidget(self.Find_button)
        Group1_layout1.addLayout(Group1_layout2)
        # --------第二个Group-------
        gather = QGroupBox('采集')
        self.gather_Layout_main = QVBoxLayout(gather)
        self.gather_Layout_radioButton = QHBoxLayout()
        self.gather_Layout_Button = QHBoxLayout()
        self.gather_radioButton1 = QRadioButton('连续模式')
        self.gather_radioButton2 = QRadioButton('触发模式')
        self.gather_Layout_radioButton.addWidget(self.gather_radioButton1)
        self.gather_Layout_radioButton.addWidget(self.gather_radioButton2)
        self.gather_Button1 = QPushButton('开始采集')
        self.gather_Button2 = QPushButton('停止采集')
        self.gather_Button3 = QPushButton('轻触发一次')
        self.gather_Button4 = QPushButton('保存图像')
        self.gather_Layout_Button.addWidget(self.gather_Button1)
        self.gather_Layout_Button.addWidget(self.gather_Button2)
        self.gather_Layout_main.addLayout(self.gather_Layout_radioButton)
        self.gather_Layout_main.addLayout(self.gather_Layout_Button)
        self.gather_Layout_main.addWidget(self.gather_Button3)
        self.gather_Layout_main.addWidget(self.gather_Button4)
        # --------第三个Group-------
        parameter = QGroupBox('参数')
        self.tabel_parameter()
        parameter_layout = QVBoxLayout(parameter)
        parameter_button_layout = QHBoxLayout()
        self.parameter_button1 = QPushButton('获取参数')
        self.parameter_button2 = QPushButton('设置参数')
        parameter_button_layout.addWidget(self.parameter_button1)
        parameter_button_layout.addWidget(self.parameter_button2)
        parameter_layout.addWidget(self.TabelParameter)
        parameter_layout.addLayout(parameter_button_layout)

        Debugger_RunModel.addWidget(initialize)
        Debugger_RunModel.addWidget(gather)
        Debugger_RunModel.addWidget(parameter)


    def continueMode(self):
        self.CameraSDK_.Set_CamMode(False)
        self.LockButton()

    def softTriggerMode(self):
        self.CameraSDK_.stop_grabbing()
        self.CameraSDK_.Set_CamMode(True)
        self.LockButton()

    def Button_Color(self):
        list_button = [self.parameter_button1,self.parameter_button2,self.gather_Button1,self.gather_Button2,
                self.gather_Button3,self.gather_Button4,self.gather_radioButton1,self.gather_radioButton2,
                self.runbutton,self.stopbutton,self.Find_button,self.Open_button,self.Close_button]
        for i in list_button:
            i.setStyleSheet('''QPushButton{background:green;border-radius:5px;}QPushButton:hover{background:blue;}''')

    def tabel_parameter(self):  #初始化表格
        self.TabelParameter = Table_widget(self,3,2)
        name_list = ["曝光", "增益", "帧率"]
        Table_widget_setItem(self.TabelParameter, name_list)
        self.spinbox(0,1,100000,20000)
        self.spinbox(1,1,10,2)
        self.spinbox(2,1,100,15)

    def spinbox(self,row,column,maxValue,startValue):  #row行 column列
        para = QSpinBox()
        para.setRange(0, maxValue)
        para.setValue(startValue)  # 设置最开始显示的数字
        para.setDisplayIntegerBase(10)  # 这个是显示数字的进制，默认是十进制。
        para.setSingleStep(1)
        self.TabelParameter.setCellWidget(row, column, para)

    def exitIndustryModel(self):
        self.stopCamera()
        self.endTimerAndThread()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = IndustryWidget_()
    w.showMaximized()
    w.show()
    sys.exit(app.exec())
